﻿using System;
using Kernelx.Contexts.Defaults;
using Kernelx.Contexts.Defaults.Sequences;
using Kernelx.Contexts.Repositories;
using Kernelx.Contexts.Defaults.RepositoriesWaylays;
using System.Linq;





#if NETSTANDARD2_0
using Microsoft.Extensions.DependencyInjection;
#endif
#if NET35
using Kernelx.Common.DependencyInjection;
#endif

namespace Kernelx.Contexts.Configuration
{ 
    /// <summary>
    /// 
    /// </summary>
    public static class WorkloadContextOptionsExtensions
    {
        /// <summary>
        /// 注册<see cref="ISequeGenerator"/>的默认实现
        /// </summary>
        /// <param name="ctxOpts"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterDefalutSequeGenerator(this WorkloadContextOptions ctxOpts, Action<SequeConfigure> action)
        {
            if (action == null)
                throw new ArgumentNullException(nameof(action));

            var opts = new SequeConfigure();
            action(opts);
            var seq = opts.Create();
            ctxOpts.Services.AddSingleton(typeof(ISequeGenerator), seq);
            return ctxOpts;
        }



        /// <summary>
        /// 注册<see cref=" IModelibOfWork"/>的拦截配置信息
        ///  
        /// </summary>
        /// <param name="ctxOpts"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterRepositoriesWaylay(this WorkloadContextOptions ctxOpts, Action<WaylaySettings> action)
        {
            if (action == null)
                throw new ArgumentNullException(nameof(action));

            var settings = new WaylaySettings();
            action(settings);

            var modelibOfWorkDes= ctxOpts.Services.FirstOrDefault(x => x.ServiceType == typeof(IModelibOfWork));
            if(modelibOfWorkDes == null)
                throw new ApplicationException($"请先注册 {nameof(IModelibOfWork)} 接口的实现类型");
             
            ctxOpts.Services.Remove(modelibOfWorkDes);
            Func<IServiceProvider, object> factory = p => new ModelibOfWorkWaylay(settings, _getModelibOfWork(p,modelibOfWorkDes) as IModelibOfWork);
            ctxOpts.Services.Add(new ServiceDescriptor(typeof(IModelibOfWork), factory, modelibOfWorkDes.Lifetime));
             
            var slaveModelibOfWorkDes = ctxOpts.Services.FirstOrDefault(x => x.ServiceType == typeof(ISlaveModelibOfWork));
            if(slaveModelibOfWorkDes != null)
            {
                ctxOpts.Services.Remove(slaveModelibOfWorkDes);
                Func<IServiceProvider, object> slaveFactory = p => new SlaveModelibOfWorkWaylay(settings, _getModelibOfWork(p, slaveModelibOfWorkDes) as ISlaveModelibOfWork);
                ctxOpts.Services.Add(new ServiceDescriptor(typeof(ISlaveModelibOfWork), slaveFactory, slaveModelibOfWorkDes.Lifetime));
            }
             
            return ctxOpts;
             
            object _getModelibOfWork(IServiceProvider provider, ServiceDescriptor  serviceDes)
            {
                if(serviceDes.ImplementationType != null) 
                    return provider.GetService(serviceDes.ImplementationType);
                else if(serviceDes.ImplementationFactory != null)
                    return serviceDes.ImplementationFactory(provider);
                else 
                    return serviceDes.ImplementationInstance;
            }
             
        }
         
    }
}
